/* 
 * -----------------------------------------------------------------------------
 * File			: syncup_db.h
 * Definition	: Interface for database manipulation for sync-up
 * -----------------------------------------------------------------------------
 */

//#include <mysql.h> // include this conflicts with <list.h>

/*
 * Option defines for each table column in update_tuple function
 */
#define UPDATE_PARENT		(1 << 0)
#define UPDATE_NAME			(1 << 1)
#define UPDATE_TIMESTAMP	(1 << 2)
#define UPDATE_CHECKSUM		(1 << 3)

#define WHERE_INODE         (1 << 4)
#define WHERE_PARENT        (1 << 5)
#define WHERE_NAME          (1 << 6)

/*
 * Data structure to hold a database entry passed in function parameter for
 * database manipulation
 * 
 * Fields		:
 * --------------
 * inode		: An integer type ID to define inode column --auto_incremented
 * parent		: An integer type ID to define parent column value
 * name			: A character string type to define the name column value
 * timestamp	: A long integer type to define the timestamp column value
 * checksum		: A character string type to define checksum column value
 *
 */
struct syncup_db_entry {
	int inode;
	int parent;
	char *name; 
	long timestamp;
	char checksum[20];
};

/*
 * Union to gather SQL query results for comparison with respect to cursor type
 */
union syncup_db_collection {
	struct {
		int inode;
		int from;
		int to;
	} moved;
	
	struct {
		int inode;
		int parent;
		char *name;
	} modified;
	
	struct {
		int inode;
	} created;
	
	struct {
		int inode;
	} removed;
	
	struct {
		int inode;
		char *name;
	} entry;
};

struct syncup_db_cursor;

/*
 * Function		: syncup_db_init
 * Description	: Database backend initializer, database and table creator for 
 *				  the syncup_db program.
 *
 * @defaul  	: server_options member for MySQL; e.g. --defaults-file=my.cnf
 * @datadir		: server_options member for MySQL; e.g. --datadir=./data
 *
 */
extern void syncup_db_init(const char *syncup_home);
extern void syncup_db_thread_init();
extern void syncup_db_thread_end();
extern void syncup_db_end();

/*
 * Function		: attach_remote_db
 * Description	: Attaches a symlink to the remote database source if there is
 *				  not one exists in local storage.
 *
 * @remoto_db_path	: Path to the remote database folder
 *
 */
extern void attach_remote_db(const char *remote_db_path);

#if 0
/*
 * Function		: cleanup_mysql
 * Description	: Closes mysql and finalizes MySQL library. 
 *
 */
extern void cleanup_mysql();

/*
 * Function		: connect_mysql
 * Description	: Attempts to establish a connection to MySQL engine.
 *
 * @mysql		: MySQL server pointer
 *
 */
extern void connect_mysql(MYSQL *mysql);

/*
 * Function		: create_db_if_not_exist
 * Description	: Creates a database with name specified if it does not exist.
 *
 * @mysql		: MySQL server pointer
 * @dbname		: Name of the database to be created
 *
 * @return		: Zero for success. Nonzero if an error occurred.
 *
 */
extern int create_db_if_not_exist(MYSQL *mysql, const char *dbname);

/*
 * Function		: select_db
 * Description	: Selects a database with name specified in order to use.
 *
 * @mysql		: MySQL server pointer
 * @dbname		: Name of the database to be selected
 * 
 * @return		: Zero for success. Nonzero if an error occurred.
 *
 */
extern int select_db(MYSQL *mysql, const char *dbname);

/*
 * Function		: create_table_if_not_exist
 * Description	: Creates a syncup table and its columns, if it does not exist.
 *
 * @mysql		: MySQL server pointer
 * @tname		: Name of the table to be created
 * 
 * @return		: Zero for success. Nonzero if an error occurred.
 *
 */
extern int create_table_if_not_exist(MYSQL *mysql, const char *tname);
#endif

/*
 * Function		: insert_new_tuple
 * Description	: Insert tuple whose columns are specified in the arguments 
 *				  into syncup table.
 *
 * @entry		: A syncup_db_entry struct type data structure
 * @to			: To which database to insert this tuple; 0=local, 1=remote
 * @checks..	: Checksum null flag; i.e. 1=null, 0:not null
 *
 * @return		: Zero for success. Nonzero if an error occurred.
 *
 */
extern int insert_new_tuple(struct syncup_db_entry *entry, int to, 
		int checksum_null);

/*
 * Function		: update_tuple
 * Description	: Updates an existing tuple in the syncup table.
 *
 * @entry		: A syncup_db_entry struct type data structure
 * @option		: Bit settings correspond to columns update; see the UPDATE
 *				  defines above.
 * @in			: In which database to update this tuple; 0=local, 1=remote
 *
 * @return		: Zero for success. Nonzero if an error occurred.
 *
 */
extern int update_tuple(struct syncup_db_entry *key, struct syncup_db_entry *ent, int option, int in);

/*
 * Function		: delete_tuple
 * Description	: Deletes a tuple specified with inode key.
 *
 * @inode		: inode of the column which is going to be deleted
 * @from		: From which database to delete this tuple; 0=local, 1=remote
 *
 * @return		: Zero for success. Nonzero if an error occurred.
 *
 */
extern int delete_tuple(struct syncup_db_entry *key, int option, int from);

/*
 * Function		: syncup_free_result
 * Description	: Fetches a row in corresponding a pointer. 
 *				  It pretty much works as mysql_fetch_row() function works.
 *
 * @cursor		: A cursor points to the query results
 *
 */
extern void syncup_free_result(struct syncup_db_cursor *cursor);

/*
 * Function		: syncup_fetch_row
 * Description	: Fetches a row in corresponding a pointer. 
 *				  It pretty much works as mysql_fetch_row() function works.
 *
 * @cursor		: A cursor points to the query results
 * @diff_data	: A union which gathers all comparison based data structs
 *
 * @return		: One for success. Zero if an error occurred.
 *
 */
extern int syncup_fetch_row(struct syncup_db_cursor *cursor, 
		union syncup_db_collection *diff_data);

/*
 * Function		: store_moved_tuples_result
 * Description	: Compares the tuples of two identical (in structure) databases,
 *				  local_db and remote_db in our case, and returns a cursor to 
 *				  the result. It pretty much works as mysql_store_result() 
 *				  function works.
 *
 * Note			: 'Move' case occurs when a tuple's parent field differs than
 *				  a corresponding field in the other database.
 *
 * SQL			: SELECT L.inode, L.parent, R.parent
 *				  FROM syncuplocaldb.syncup L, syncupremotedb.syncup R
 *				  WHERE L.inode = R.inode AND L.parent <> R.parent
 *
 * @return		: A syncup_db_cursor to the result 
 *				  The column values returned by each tuple is in this order:
 *				  inode(local), parent(local), parent(remote)
 *
 */
extern struct syncup_db_cursor* store_moved_tuples_result();

/*
 * Function		: store_modified_tuples_result
 * Description	: Compares the tuples of two identical (in structure) databases,
 *				  local_db and remote_db in our case, and returns a cursor to 
 *				  the result. It pretty much works as mysql_store_result() 
 *				  function works.
 *
 * Note			: 'Modified' case occurs when a tuple's checksum field differs 
 *				  than a corresponding field in the other database.
 *
 * SQL			: SELECT L.inode, L.checksum, R.checksum
 *				  FROM syncuplocaldb.syncup L, syncupremotedb.syncup R
 *				  WHERE L.inode = R.inode AND L.checksum <> R.checksum
 *
 * @return		: A syncup_db_cursor to the result 
 *				  The column values returned by each tuple is in this order:
 *				  inode(local), checksum(local), checksum(remote)
 *
 */
extern struct syncup_db_cursor* store_modified_tuples_result();

/*
 * Function		: store_created_tuples_result
 * Description	: Compares the tuples of two identical (in structure) databases,
 *				  local_db and remote_db in our case, and returns a cursor to 
 *				  the result. It pretty much works as mysql_store_result() 
 *				  function works.
 *
 * Note			: 'Created' case occurs when a tuple's inode exist in local
 *				  side, but not in remote side
 *
 * SQL			: SELECT L.inode
 *				  FROM syncuplocaldb.syncup L
 *				  LEFT OUTER JOIN syncupremotedb.syncup R
 *				  ON L.inode = R.inode
 *				  WHERE R.inode IS NULL
 *
 * @return		: A syncup_db_cursor to the result 
 *				  The column values returned by each tuple is in this order:
 *				  inode(local)
 *
 */
extern struct syncup_db_cursor* store_created_tuples_result();

/*
 * Function		: store_removed_tuples_result
 * Description	: Compares the tuples of two identical (in structure) databases,
 *				  local_db and remote_db in our case, and returns a cursor to 
 *				  the result. It pretty much works as mysql_store_result() 
 *				  function works.
 *
 * Note			: 'Removed' case occurs when a tuple's inode exist in remote
 *				  side, but not in local side
 *
 * SQL			: SELECT R.inode
 *				  FROM syncuplocaldb.syncup L
 *				  RIGHT OUTER JOIN syncupremotedb.syncup R
 *				  ON L.inode = R.inode
 *				  WHERE L.inode IS NULL
 *
 * @return		: A syncup_db_cursor to the result 
 *				  The column values returned by each tuple is in this order:
 *				  inode(remote)
 *
 */
extern struct syncup_db_cursor* store_removed_tuples_result();

/*
 * Function		: store_entry_tuples_result
 * Description	: Store the entry tuples where their checksums are null and 
 *				  parent IDs are equal to inode.
 *
 * @inode		: inode of an entry tuple
 *
 * SQL			: SELECT L.inode, L.name
 *				  FROM syncuplocaldb.syncup L
 *				  WHERE L.checksum = null AND L.parent = @param inode
 *
 * @return		: A syncup_db_cursor to the result 
 *				  The column values returned by each tuple is in this order:
 *				  inode(local), name(local)
 *
 */
extern struct syncup_db_cursor* store_entry_tuples_result(int inode);

/* For testing */
extern int syncup_db_test_thread_safe();

extern void syncup_db_lock_query();
extern void syncup_db_unlock_query();

